package com.jmp.autocofiguration.web.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.exception.ParamException;
import one.stand.util.RequestContext;
import one.stand.util.RequestContextHolder;
import one.stand.util.Sha256Util;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;

/**
 * 参数处理
 *
 * @author Administrator
 */
@Slf4j
public class ParamCheckInterceptor implements HandlerInterceptor {

    private final String PARAMETER_DATA = "data";
    private final String ATTRIBUTE_REQUEST = "request";

    private Map<String, Class> map = Maps.newHashMap();

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        try {

            String data = httpServletRequest.getParameter(PARAMETER_DATA);
            Class<?> clazz = getParamType(o);

            if (Objects.nonNull(clazz)) {
                JSONObject json = null;
                if (StringUtils.isNoneBlank(data)) {
                    String decodeData = decode(data);
                    json = JSONObject.parseObject(decodeData);
                }

                // todo 兼容以前代码中请求参数继承TokenRequest
                RequestContext requestContext = RequestContextHolder.getRequestContext();
                if (Objects.isNull(json)) {
                    json = new JSONObject();
                }
                json.put("token", requestContext.getRequest().getToken());
                json.put("ip", requestContext.getRequest().getIp());
                json.put("companyKey", requestContext.getRequest().getCompanyKey());
                if (requestContext.isLogin()) {
                    RequestContext.User user = requestContext.getUser();
                    json.put("id", user.getUserId());
                    json.put("cId", user.getCompanyId());
                    json.put("roleId", user.getRoleId());
                    json.put("myCardId", user.getCardId());
                    json.put("loginProgramName", user.getLoginProgramName());
//                    json.put("logintime", request.getLogintime());
                    json.put("companyKey", user.getCompanyKey());
                }

                httpServletRequest.setAttribute(ATTRIBUTE_REQUEST, json.toJavaObject(clazz));
//                httpServletRequest.setAttribute(ATTRIBUTE_REQUEST, JSON.parseObject(data, clazz));
            }

            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ParamException(ResultEnum.PARAM_CHECK.getMessage());
        }
    }

    private String decode(String data) throws Exception {
        log.info("参数: {}", data);
        String dataJson = Sha256Util.base64ToString(data);
        log.debug("参数解密: {}", dataJson);
        return dataJson;
    }

    private Class<?> getParamType(Object handler) {
        Class<?> clazz = null;
        if (handler instanceof HandlerMethod) {
            HandlerMethod h = (HandlerMethod) handler;

            String methodStr = h.getMethod().toString();
            clazz = map.get(methodStr);
            if (Objects.nonNull(clazz)) {
                return clazz;
            }

            MethodParameter[] methodParameters = h.getMethodParameters();
            if (methodParameters.length > 0) {

                for (MethodParameter methodParameter : methodParameters) {
                    if (Objects.equals(methodParameter.getParameter().getName(), ATTRIBUTE_REQUEST)
                            && Objects.nonNull(methodParameter.getParameterAnnotation(RequestAttribute.class))
                    ) {
                        clazz = methodParameter.getParameterType();
                        break;
                    }
                }
            }
            if (Objects.nonNull(clazz)) {
                map.put(methodStr, clazz);
            }

        }

        return clazz;
    }
}
